<?php
Zend_Loader::loadClass('Lead_EDO_Handler_Persist_Functional_IdentityMap');
Zend_Loader::loadClass('Lead_EDO_Handler_Persist_Functional_UnitOfWork');

class Lead_EDO_Handler_Persist_Functional
{
    private $_handler;
    private $_db;
    private $_identityMap;
    private $_unitOfWork;    
    
    private static $_queries;
    
    
    public function __construct(Lead_Edo_Handler_Interface $handler)
    {
        $this->_handler = $handler;
        $this->_db = $handler->getDB();
        $this->_identityMap = new Lead_EDO_Handler_Persist_Functional_IdentityMap();
        $this->_unitOfWork = new Lead_EDO_Handler_Persist_Functional_UnitOfWork($this->_db, $this->_identityMap);
    }
       
    
    public function insert(Lead_EDO_Object_Abstract $obj) 
    {
        $obj->id = $this->_db->nextId('id');
        $this->_identityMap->set($obj);
        $this->_unitOfWork->registerNew($obj);
    }
    
    
    public function save(Lead_EDO_Object_Abstract $obj)
    {
        $this->_unitOfWork->registerDirty($obj);
    }


    public function delete(Lead_EDO_Object_Abstract $obj)
    {
        $this->_unitOfWork->registerDeleted($obj);
    }
    
    
	
	public function fetch($id, $type = null)
	{
	    if($edo = $this->_identityMap->get($id))
	        return $edo;
	    	    
	    if(!$type) {
       	    $phrase = "SELECT type_id FROM edo WHERE id = {$id}";
          	$type = $this->_db->fetchOne($phrase);
          	
          	if(!$type)
          	    throw new Lead_EDO_Exception("Fetch failed with id: {$id}");
          	
	    }
        	    
	    
	    if(is_numeric($type))
            $type = $this->_handler->convert($type);

        $edo = $this->_handler->get($type);
	    
	    if(!$this->_handler->getCache()) {
            $phrase = $this->_getFetchQuery($edo) . "WHERE {$edo->getType()->getFirstTable()}.id = {$id}";
            $row = $this->_db->fetchRow($phrase);
	    } else {
	        $cache = $this->_handler->getCacheFrontend();
            if(!$row = $cache->load("entity_{$id}")) {
	            $phrase = $this->_getFetchQuery($edo) . "WHERE {$edo->getType()->getFirstTable()}.id = {$id}";
	            $row = $this->_db->fetchRow($phrase);
	            $cache->save($row, "entity_{$id}");
    	    }
	    }    	    
	    
		if($row)
		{
			$edo->setFields($row, false);
			$edo->setFetched(true);
			
			$this->_identityMap->set($edo);
			$this->_unitOfWork->registerClean($edo);
			
			return $edo;
		}


		throw new Lead_EDO_Exception("Fetch failed with id: {$id}");
		
	}
	
	
	private function _getFetchQuery(Lead_EDO_Object_Abstract $obj)
	{
   		if(!isset(self::$_queries[$obj->getClass()]['fetch']))
		{
			$phrase = "SELECT * FROM {$obj->getType()->getFirstTable()} ";

			foreach($this->_handler->getType($obj)->getRestOfTables() as $table)
			{
                if(!$this->_handler->getType($obj)->tableIsDimensional($table))
                    $phrase .= "JOIN {$table} ON ({$obj->getType()->getFirstTable()}.id = {$table}.id) ";
                else
                {
                    $dimensionid = call_user_func($obj->getHandler()->getAttribute('Callback_GetDimension'));
                    $phrase .= "JOIN {$table} ON ({$obj->getType()->getFirstTable()}.id = {$table}.id AND {$table}.dimension_id = {$dimensionid}) ";
                }
			}

			self::$_queries[$obj->getClass()]['fetch'] = $phrase;
		}
		
		/*
		print" <hr />";
		print self::$_queries[$obj->getClass()]['fetch'];
		print "<hr />";
        */
		

		return self::$_queries[$obj->getClass()]['fetch'];

	}
	
	
	public function commit()
	{
	    $this->_unitOfWork->commit();
	}

	public function rollback()
	{
	    $this->_unitOfWork->rollback();
	}
	
	
}
